#include "number.h"

Complex* complex_im (Complex* complex)
{
    Interval* re = interval_dup(complex->im);
    Interval* im = interval_zero();
    
    return complex_new(re, im);
}

Complex* complex_im_l (Complex* complex)
{
    Real* real = real_dup(complex->im->l);
    return complex_from_real(real);
}

Complex* complex_im_n (Complex* complex)
{
    Real* real = real_dup(complex->im->n);
    return complex_from_real(real);
}

Complex* complex_im_u (Complex* complex)
{
    Real* real = real_dup(complex->im->u);
    return complex_from_real(real);
}

Complex* complex_im_magnitude (Complex* complex)
{
    Complex* result;
    
    Real* l_abs = real_abs(complex->im->l);
    Real* u_abs = real_abs(complex->im->u);
    
    if (real_gt_p(l_abs, u_abs))
    {
        result = complex_from_real(l_abs);
        real_free(u_abs);
    }
    else
    {
        result = complex_from_real(u_abs);
        real_free(l_abs);
    }
    
    return result;
}

Complex* complex_im_mignitude (Complex* complex)
{
    Complex* result;
    
    Real* l_abs = real_abs(complex->im->l);
    Real* u_abs = real_abs(complex->im->u);
    
    if (interval_span_zero_p(complex->im))
    {
        result = complex_zero();
        real_free(l_abs);
        real_free(u_abs);
    }
    else if (real_lt_p(l_abs, u_abs))
    {
        result = complex_from_real(l_abs);
        real_free(u_abs);
    }
    else
    {
        result = complex_from_real(u_abs);
        real_free(l_abs);
    }
    
    return result;
}

Complex* complex_im_width (Complex* complex)
{
    Real* real = real_subtract(complex->im->u, complex->im->l);
    return complex_from_real(real);
}

Complex* complex_re (Complex* complex)
{
    Interval* re = interval_dup(complex->re);
    Interval* im = interval_zero();
    
    return complex_new(re, im);
}

Complex* complex_re_l (Complex* complex)
{
    Real* real = real_dup(complex->re->l);
    return complex_from_real(real);
}

Complex* complex_re_n (Complex* complex)
{
    Real* real = real_dup(complex->re->n);
    return complex_from_real(real);
}

Complex* complex_re_u (Complex* complex)
{
    Real* real = real_dup(complex->re->u);
    return complex_from_real(real);
}

Complex* complex_re_magnitude (Complex* complex)
{
    Complex* result;
    
    Real* l_abs = real_abs(complex->re->l);
    Real* u_abs = real_abs(complex->re->u);
    
    if (real_gt_p(l_abs, u_abs))
    {
        result = complex_from_real(l_abs);
        real_free(u_abs);
    }
    else
    {
        result = complex_from_real(u_abs);
        real_free(l_abs);
    }
    
    return result;
}

Complex* complex_re_mignitude (Complex* complex)
{
    Complex* result;
    
    Real* l_abs = real_abs(complex->re->l);
    Real* u_abs = real_abs(complex->re->u);
    
    if (interval_span_zero_p(complex->re))
    {
        result = complex_zero();
        real_free(l_abs);
        real_free(u_abs);
    }
    else if (real_lt_p(l_abs, u_abs))
    {
        result = complex_from_real(l_abs);
        real_free(u_abs);
    }
    else
    {
        result = complex_from_real(u_abs);
        real_free(l_abs);
    }
    
    return result;
}

Complex* complex_re_width (Complex* complex)
{
    Real* real = real_subtract(complex->re->u, complex->re->l);
    return complex_from_real(real);
}

Complex* complex_ll (Complex* complex)
{
    Interval* re = interval_from_real(real_dup(complex->re->l));
    Interval* im = interval_from_real(real_dup(complex->im->l));
    
    return complex_new(re, im);
}

Complex* complex_lu (Complex* complex)
{
    Interval* re = interval_from_real(real_dup(complex->re->l));
    Interval* im = interval_from_real(real_dup(complex->im->u));
    
    return complex_new(re, im);
}

Complex* complex_n (Complex* complex)
{
    Interval* re = interval_from_real(real_dup(complex->re->n));
    Interval* im = interval_from_real(real_dup(complex->im->n));
    
    return complex_new(re, im);
}

Complex* complex_ul (Complex* complex)
{
    Interval* re = interval_from_real(real_dup(complex->re->u));
    Interval* im = interval_from_real(real_dup(complex->im->l));
    
    return complex_new(re, im);
}

Complex* complex_uu (Complex* complex)
{
    Interval* re = interval_from_real(real_dup(complex->re->u));
    Interval* im = interval_from_real(real_dup(complex->im->u));
    
    return complex_new(re, im);
}

Complex* complex_magnitude (Complex* complex)
{
    Interval* re;
    Interval* im;
    
    Real* re_l_abs = real_abs(complex->re->l);
    Real* re_u_abs = real_abs(complex->re->u);
    Real* im_l_abs = real_abs(complex->im->l);
    Real* im_u_abs = real_abs(complex->im->u);
    
    if (real_gt_p(re_l_abs, re_u_abs))
    {
        re = interval_from_real(re_l_abs);
        real_free(re_u_abs);
    }
    else
    {
        re = interval_from_real(re_u_abs);
        real_free(re_l_abs);
    }
    
    if (real_gt_p(im_l_abs, im_u_abs))
    {
        im = interval_from_real(im_l_abs);
        real_free(im_u_abs);
    }
    else
    {
        im = interval_from_real(im_u_abs);
        real_free(im_l_abs);
    }
    
    return complex_new(re, im);
}

Complex* complex_mignitude (Complex* complex)
{
    Interval* re;
    Interval* im;
    
    Real* re_l_abs = real_abs(complex->re->l);
    Real* re_u_abs = real_abs(complex->re->u);
    Real* im_l_abs = real_abs(complex->im->l);
    Real* im_u_abs = real_abs(complex->im->u);
    
    if (interval_span_zero_p(complex->re))
    {
        re = interval_zero();
        real_free(re_l_abs);
        real_free(re_u_abs);
    }
    else if (real_lt_p(re_l_abs, re_u_abs))
    {
        re = interval_from_real(re_l_abs);
        real_free(re_u_abs);
    }
    else
    {
        re = interval_from_real(re_u_abs);
        real_free(re_l_abs);
    }
    
    if (interval_span_zero_p(complex->im))
    {
        im = interval_zero();
        real_free(im_l_abs);
        real_free(im_u_abs);
    }
    else if (real_lt_p(im_l_abs, im_u_abs))
    {
        im = interval_from_real(im_l_abs);
        real_free(im_u_abs);
    }
    else
    {
        im = interval_from_real(im_u_abs);
        real_free(im_l_abs);
    }
    
    return complex_new(re, im);
}

Complex* complex_width (Complex* complex)
{
    Real* re_width = real_subtract(complex->re->u, complex->re->l);
    Real* im_width = real_subtract(complex->im->u, complex->im->l);
    
    Interval* re = interval_from_real(re_width);
    Interval* im = interval_from_real(im_width);
    
    return complex_new(re, im);
}
